/*
* Copyright (C) 2014 Shashank Tulsyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package neembuu.diskmanager.impl.session;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.channels.SeekableByteChannel;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.OpenOption;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.LinkedList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import neembuu.diskmanager.DiskManagerParams;
import neembuu.diskmanager.FileStorageManager;
import neembuu.diskmanager.FileStorageManagerParams;
import neembuu.diskmanager.LoggerCreateSPI;
import neembuu.diskmanager.NioUtils;
import neembuu.diskmanager.Session;
import neembuu.diskmanager.impl.CloseCallback;
import neembuu.diskmanager.impl.DefaultFileStorageManager;
import neembuu.diskmanager.impl.JavaStringHashAlgo;
import neembuu.diskmanager.impl.Utils;
import neembuu.diskmanager.impl.channel.ChannelList;
/**
*
* @author Shashank Tulsyan
*/
public class DefaultSession implements Session {
private final String type;
private final DiskManagerParams dmp;
private final Path sessionPath;
private boolean restoredCorrectly = false;
private final ChannelList resources = new ChannelList();
private final List<FileStorageManager> fsms = new LinkedList<FileStorageManager>();
public DefaultSession(String type, Path p, DiskManagerParams dmp) {
this.type = type; this.dmp = dmp;this.sessionPath = p;
restoredCorrectly = isValid(p, type, dmp);
}
static boolean isValid(Path p, String type, DiskManagerParams dmp){
if(!Files.exists(p.resolve(dmp.getNomenclature().sessionMetaDataFileName()))){
return false;
}
try{
String sessionFileName = p.getFileName().toString();
String metaHash = dmp.getNomenclature().getSessionName(sessionFileName).getMetaHash();
//boolean typeValid = checkType(p, type); if(!typeValid)return false;
boolean hashValid = hashCheck(p, metaHash,dmp);
return hashValid;
}catch(Exception a){ /*ignore*/ }
return false;
}
public Path getSessionPath() {
return sessionPath;
}
/*private static boolean checkType(Path p,String type){
try{
Path typeFile = p.resolve("type");
if(Files.exists(typeFile)){
List<String> lines = Files.readAllLines(p, StandardCharsets.US_ASCII);
for (String line : lines) {
if(line.equalsIgnoreCase(type))return true;
}
}
}catch(Exception a){}return false;
}*/
private static boolean hashCheck(Path p,String metaHash,DiskManagerParams dmp){
try{
Path metaDataFile = p.resolve(dmp.getNomenclature().sessionMetaDataFileName());
if(Files.exists(metaDataFile)){
try ( FileChannel fc = FileChannel.open(metaDataFile, StandardOpenOption.READ) ) {
ByteBuffer bb = JavaStringHashAlgo.makeByteBuffer(fc);
String hasCodeStr = JavaStringHashAlgo.makeHash(bb).getAsString();
if(metaHash.startsWith(hasCodeStr)){
return true;
}
}catch(Exception a){
}
}
}catch(Exception a){
}return false;
}
@Override public FileStorageManager makeNewFileStorageManager(FileStorageManagerParams fsmp) {
final FileStorageManager fsm;
try{
fsm = new DefaultFileStorageManager(dmp,fsmp,sessionPath,
new CloseCallback<DefaultFileStorageManager>() {
@Override public void closed(DefaultFileStorageManager e) { fsms.remove(e); }}
);
fsms.add(fsm);
}catch(IOException ioe){
throw new RuntimeException(ioe);
}
return fsm;
}
@Override public String getType() {
return type;
}
@Override
public SeekableByteChannel openMetaData()throws IOException {
/*if(!restoredCorrectly()){
throw new IllegalStateException("Invalid session");
}*/
return resources.addAndGet(FileChannel.open(
sessionPath.resolve(dmp.getNomenclature().sessionMetaDataFileName()), StandardOpenOption.READ));
}
@Override
public boolean restoredCorrectly() {
return restoredCorrectly;
}
@Override
public SeekableByteChannel getOrCreateResource(String nm, OpenOption... openOptions) throws Exception{
return resources.addAndGet(FileChannel.open(sessionPath.resolve(nm), openOptions));
}
@Override
public Logger createLogger(String nm) {
nm = dmp.getNomenclature().getLogStorage().make(nm);
return Utils.createLogger(nm, dmp, this, LoggerCreateSPI.Type.Session);
}
@Override
public void delete() throws Exception {
close();
NioUtils.deleteDirectory(sessionPath);
}
@Override
public void clearCachedFileData() throws Exception {
Exception aggregate = null;
try (DirectoryStream<Path> ds = Files.newDirectoryStream(sessionPath)){
for(Path p : ds){
if(Files.isDirectory(p)){
try{NioUtils.deleteDirectory(p);}catch(Exception a){
if(aggregate==null){aggregate = a;}else {aggregate.addSuppressed(a);}}
}
}
} catch (IOException ex) {
if(aggregate==null){aggregate = ex;}else {aggregate.addSuppressed(ex);}
}
if(aggregate!=null)throw aggregate;
}
@Override
public void close()throws Exception{
synchronized (resources){
resources.close();
}
for (FileStorageManager fsm : fsms) {
fsm.close();
}
}
}